#ifdef _DEBUG
#pragma comment(linker, "/SUBSYSTEM:Console")
#else
#pragma comment(linker, "/SUBSYSTEM:Windows")
#endif _DEBUG

#define _CRTDBG_MAP_ALLOC
#include <windows.h>
#include <process.h>	// Include Multi-Threading functions:
#include <ctime>	//time() for random seed
#include "CGameClass.h"
#include "Includes.h"
#include "CRender.h"
#include "CCamera.h"
#include "gltools.h"

// Enable VisualStudio built-in memory leak detector
// when using new and delete in debug mode.
#include <crtdbg.h>
#ifdef _DEBUG
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif

//--------------------------------------------------------------------------
// prototypes.
bool InitWindow(HWND& wnd, HINSTANCE& app);							// initialize window

//unsigned int WINAPI GameMain(void* lpvArgList);

int WINAPI WinMain(HINSTANCE hInstance,		// handle to application
				   HINSTANCE hPrevInstance,	// handle to previous app
				   LPSTR lpCmdLine,		// command line string
				   int nCmdShow );			// show window value

LRESULT CALLBACK WndProc(HWND hWnd,				// handle to window
						 UINT message,			// incoming message
						 WPARAM wparam,			// message info
						 LPARAM lparam );		// message info

// Entry point function for the game:
//unsigned int WINAPI GameMain(void* lpvArgList)
//{
//	HWND hWnd = static_cast<HWND>( static_cast<void**>(lpvArgList)[0] );
//	HINSTANCE hInstance = static_cast<HINSTANCE>( static_cast<void**>(lpvArgList)[1] );
//	//////////////////////////////////////////
//	//	Initialize Game here
//	//////////////////////////////////////////
//	CGame* pGame = CGame::GetInstance();
//
//	//pGame->Initialize(hWnd, hInstance, g_nWINDOW_WIDTH, g_nWINDOW_HEIGHT, g_bIS_WINDOWED);
//
//	//InitGame();				// initialize game
//	pGame->Init(&hWnd, &hInstance, (float)DEFAULT_WINDOWED_WIDTH, (float)DEFAULT_WINDOWED_HEIGHT);
//
//	// MAIN GAME LOOP!
//	while( pGame->GameLoop() ) { }
//	/////////////////////////////////////////
//	//	Shutdown Game Here
//	/////////////////////////////////////////
//	pGame->Shutdown();
//	//EndGame();						// game shutdown and cleanup
//
//	PostMessage(hWnd, WM_QUIT, 0, 0);
//	return 0;
//}
//////////////////////////
//		Console			//
//////////////////////////

void main(int argc, char** argv)
{
	// this will only be run in debug, set the memory leak detection flags
	_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	_CrtSetBreakAlloc(0);

	//AllocConsole();

	// run WinMain, there will be a console as well as the normal game
	WinMain(GetModuleHandle(NULL), NULL, (LPSTR)GetCommandLine(), SW_SHOWDEFAULT);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
{
	HINSTANCE					app;
	HWND						wnd;

    app = hInstance;		// store application handle
    InitWindow(wnd, app);			// init window

    MSG msg; ZeroMemory( &msg, sizeof( msg ) );  // use to catch windows messages
	
	/////////////////////////////////////////////////////////////
	/// windows proc and game loop on the same thread
	/////////////////////////////////////////////////////////////
	CGameClass* pGame = CGameClass::GetInstance();
	pGame->Init( &wnd, &app, DEFAULT_WINDOWED_WIDTH, DEFAULT_WINDOWED_HEIGHT);
	while ( msg.message != WM_QUIT ) {
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{  TranslateMessage( &msg ); DispatchMessage( &msg ); }
		// MAIN GAME LOOP!
		if( !pGame->GameLoop() )
			break;
	}
	pGame->Shutdown();
	/////////////////////////////////////////////////////////////
	/// windows proc and game loop on separate threads
	/////////////////////////////////////////////////////////////
	//void* h[2];
	//h[0] = wnd;
	//h[1] = app;
	//HANDLE hGameThread = (HANDLE)_beginthreadex(NULL, 0, GameMain, h, 0, NULL);
	//while (GetMessage(&msg, NULL, 0, 0))
	//{
	//	if (!TranslateAccelerator(msg.hwnd, 0, &msg))
	//	{
	//		TranslateMessage(&msg);
	//		DispatchMessage(&msg);
	//	}
	//}
	//// Wait until Game Thread terminates:
	//WaitForSingleObject(hGameThread, INFINITE);
	//// Destroy the Game Thread:
	//CloseHandle(hGameThread);

    UnregisterClass( "research project", app ); // unregister window
	_CrtDumpMemoryLeaks();
    return 0; // done
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	static HDC	hDC = NULL;	
	static HGLRC hRC = NULL;

    // attempt to handle
    switch ( message )
    {
		case WM_CREATE: 
		{
			//	Do initialization here
			hDC = GetDC(hWnd);

			static PIXELFORMATDESCRIPTOR pfd = {
				sizeof(PIXELFORMATDESCRIPTOR),		// Size of struct
				1,									// Version of struct
				PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // 
				PFD_TYPE_RGBA,	// Always put this
				32,				// Always put this, size of the color buffer
				0,0,0,0,0,0,0,0,0,0,0,0,0, // You have no control over
				16,					       // Depth of the Z buffer
				8,				// Stencil buffer
				0,0,0,0,0,0 };	// Either obsolete, or we don't care about

			int nPF = ChoosePixelFormat(hDC, &pfd);

			SetPixelFormat(hDC, nPF, &pfd);

			// Create rendering context
			hRC = wglCreateContext(hDC);
			wglMakeCurrent(hDC, hRC);
			CRender::GetInstance()->InitOpenGL();
			CCamera::GetInstance()->SetPosition(0, 0, 45);
			CCamera::GetInstance()->LookAt(0, 0, 0);
			return(0);
		}
		break;
			//	Handle ALT+F4
		case WM_CLOSE:
			{
				// set the games bool running to false
				//CGameClass::GetInstance()->SetRunning(FALSE);
				// Sends us a WM_DESTROY
				DestroyWindow(hWnd);			
			}
			break;

			//	and lose/gain focus
		case WM_EXITSIZEMOVE:
			// pg95 frank luna
			break;
		case WM_ACTIVATE:
			{
				// 1. PAUSE THE GAME when you LOSE FOCUS, 
				// 2. RELEASE everything that pertains to 3D models
				// 3. Reload everything pertaining to 3D models
				// 4. UNPAUSE the game

				//	gaining focus
				if (LOWORD(wParam) != WA_INACTIVE)
				{
					// unpause game code here
				}
				else // losing focus
				{
					// pause game code here
				}
			}
			break;
		case WM_DESTROY: 
		{
			//	Kill the application
			CRender::GetInstance()->Shutdown();
			wglMakeCurrent(hDC, NULL);
			wglDeleteContext(hRC);
			ReleaseDC(hWnd, hDC);
			PostQuitMessage(0);
			return(0);
		}
		case WM_SIZE:
		{
			//glPushMatrix();
			//CCamera::GetInstance()->ApplyCameraMatrix();
			CRender::GetInstance()->Resize(LOWORD(lParam), HIWORD(lParam));
			//glPopMatrix();
		}
		break;
		case WM_PAINT:
		{
			SwapBuffers(hDC);
			glPushMatrix();
			CCamera::GetInstance()->ApplyCameraMatrix();
			CRender::GetInstance()->Render();
			glPopMatrix();
			return(0);
		}
		break;
    }
    // pass to default handler
    return DefWindowProc( hWnd, message, wParam, lParam );
}

bool InitWindow(HWND &wnd, HINSTANCE &app)
{   
    WNDCLASSEX  wndClass;

    // register a new type of window
    ZeroMemory( &wndClass, sizeof( wndClass ) );
    wndClass.cbSize         = sizeof( WNDCLASSEX );             // size of window structure
    wndClass.lpfnWndProc    = ( WNDPROC )WndProc;               // message callback
    wndClass.lpszClassName  = "GGJ10";							// class name
    wndClass.hInstance      = app;								// handle to application
    wndClass.hCursor        = LoadCursor( NULL, IDC_ARROW );    // default cursor
    wndClass.hbrBackground  = ( HBRUSH )( COLOR_WINDOWFRAME );  // background brush
    RegisterClassEx( &wndClass );

    // create window of registered type
    wnd = CreateWindow(
        "GGJ10", "GGJ10",								// class name, window title 
		WS_OVERLAPPEDWINDOW,									// window style
        CW_USEDEFAULT, CW_USEDEFAULT,                           // x & y coordinates
        800, 800,        // width & height of window
        NULL, NULL,                                             // parent window & menu
        app,													// handle to application
        NULL );

    // take a guess
    ShowWindow( wnd, SW_SHOW );                           // technically should be nCmdShow

	CRender::GetInstance()->InitOpenGL();
    return true;
}

